from django.template import loader, RequestContext
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django.db.transaction import commit_on_success
from django.db.models.loading import get_model
from django.conf import settings
from django import newforms as forms
from duetopia.register.models import DataSet, DataSource, DataFormat, TimePeriod, Agent
#from duetopia.register.forms import DatasetShortForm, DatasetContactForm, DatasetTextForm, DatasetExtentsForm
from duetopia.register.forms import DatasetShortForm #, DataSourceForm
from duetopia.register.fields import NoAgent, NoUniqueAgent
from duetopia.register.views.generic import edit_object

from warnings import warn

__all__ = ['view_dataset', 'add_datasource','view_datasource','add_dataset','extend_dataset','edit_timespan','add_dataset_extents','detach_dataset_agent','edit_format']

def view_dataset(request, pk, template='register/view_dataset.html'):
    dataset = get_object_or_404(DataSet, pk=pk)
    context = {
        'dataset': dataset,
        'tilecache': settings.TILECACHE,
        'baseurl': settings.WWW_BASEURL,
    }
    c = RequestContext(request, context)
    t = loader.get_template(template)
    return HttpResponse(t.render(c))

def view_datasource(request, pk, template='register/view_datasource.html'):
	datasource = get_object_or_404(DataSource, pk=pk)
	context = {
		'dataset' : datasource.dataset,
        'datasource': datasource,
        'tilecache': settings.TILECACHE,
        'baseurl' : settings.WWW_BASEURL,
	}
	c = RequestContext(request, context)
	t = loader.get_template(template)
	return HttpResponse(t.render(c))


def add_datasource(request, ds_pk=None,template='register/add_datasource.html'):

    #Form = DataSourceForm
    Form = forms.form_for_model(DataSource) # only used for validation
    dataset = datasource = None
    if ds_pk is not None:
        dataset = DataSet.objects.get(pk=ds_pk)        
#    Form = forms.form_for_model(DataSet)
    if not request.POST:  ## empty form data
        form = Form()

    else: 
    ## check if data source exists, redirect to its dataset
        if 'uri' in request.POST:
            filter = DataSource.objects.filter(uri = request.POST['uri'])
            if filter: # we already know about this URI - see edit page
                datasource = filter.get()
                redirect_to = '/duetopia/register/dataset/%s/' % datasource.dataset.id
                return HttpResponseRedirect(redirect_to)

		## validate form data and save
        try:
            form = Form(request.POST)
            format = None
            if request.POST['format'] : 
                format = DataFormat.objects.get(id=request.POST['format'])

            if form.is_valid():

                datasource = DataSource()
                datasource.uri = request.POST['uri']
                datasource.format = format 
                datasource.dataset = dataset
                #d.uri = request.POST['uri']
                datasource.save()
            
            redirect_to = None
            if dataset:    
                redirect_to = '/duetopia/register/dataset/%s/' % dataset.id
            else:
                redirect_to = '/duetopia/register/datasource/%s/' % datasource.id
            return HttpResponseRedirect(redirect_to)

        except Exception, e:
            form = Form(request.POST)
            form.errors['uri'] = (_('Could not interpret URI: %s' % e),)

    context = {
        'form' : form,
        'dataset': dataset,
        'object': datasource,
        'formats': DataFormat.objects.filter(),
        'baseurl': settings.WWW_BASEURL,
    }

    c = RequestContext(request, context)
    t = loader.get_template(template)
    return HttpResponse(t.render(c))

# we finally give up on django's form generation to do this.

def add_dataset(request, template='register/add_dataset.html'):
    
    if not request.POST:  ## empty form data
        form = DatasetShortForm()
    else: ## validate form data
        form = DatasetShortForm(request.POST)
        try:
            if form.is_valid():
                # we r lazy
                F = forms.form_for_model(DataSet)
                form = F(request.POST)
                object = form.save()
                # here, go on to add more properties
                redirect_to = settings.WWW_BASEURL+'dataset/%s/' % object.id
                return HttpResponseRedirect(redirect_to)
        except ValueError:
            pass
        

    context = {
        'form' : form,
    }

    c = RequestContext(request, context)
    t = loader.get_template(template)
    return HttpResponse(t.render(c))

def extend_dataset(request,pk,extra=None,template='register/extend_dataset.html'):
    # select from different update segments in forms.py
    # 'fields' allows us to display a different subset of form options
    object = get_object_or_404(DataSet,pk=pk)

    ### utility function
    def hide_others(Form, visible):
        for name, field in Form.base_fields.iteritems():
            if name not in visible:
                field.widget = field.hidden_widget()

    ### fork to other handlers if necessary
    if extra == 'timespan':
        redirect_to = '/duetopia/register/timespan/for/dataset/%s/' % object.id
        return HttpResponseRedirect(redirect_to)
    elif extra == 'extents':
        redirect_to = '/duetopia/register/extents/for/%s/' % object.id
        return HttpResponseRedirect(redirect_to)

    ### construct the appropriate form class
    if not request.POST or "dataset-title" in request.POST:
        # generic edit form
        Form = forms.form_for_instance(object)
        # custom/subset edit forms
        if extra == 'contact':
            hide_others(Form, ["contacts"])
        elif extra == 'text':
            hide_others(Form, ["title","keywords", "abstract"])
        elif extra == 'dates':
            hide_others(Form, ["published","updated"])
    elif "agent-name" in request.POST:
        ### a special form class where the save method
        ### adds the resulting agent to the dataset object
        ### note scoping -- "object" comes from above
        class Form(forms.form_for_model(Agent)):
            def save(self):
                agent = super(Form, self).save()
                if not object.contacts.filter(pk=agent.id):
                    object.contacts.add(agent)
    elif "agent_select-agents" in request.POST:
        ### this form is used for validation when multiple agents
        ### match the search criteria. note that it only 
        ### validates that the agent *exists* since we don't have
        ### the original narrowed down list anymore. note also
        ### scoping of "object" from above.
        choices = [(a.id, str(a)) for a in Agent.objects.filter()]
        class Form(forms.Form):
            agents = forms.MultipleChoiceField(choices=choices)
            def save(self):
                if not self.is_valid(): raise ValueError
                for id in self.cleaned_data["agents"]:
                    if not object.contacts.filter(pk=id):
                        agent = Agent.objects.get(pk=id)
                        object.contacts.add(agent)


    ### instantiate the appropriate form object
    if not request.POST:
        form = Form(prefix="dataset")
    elif "dataset-title" in request.POST:
        form = Form(request.POST, prefix="dataset")
    elif "agent-name" in request.POST:
        form = Form(request.POST, prefix="agent")
    elif "agent_select-agents" in request.POST:
        form = Form(request.POST, prefix="agent_select")

    ### process the form 
    if request.POST:
        try:
            @commit_on_success
            def validate(form):
                return form.save()
            validate(form)
            redirect_to = settings.WWW_BASEURL+'dataset/%s/' % object.id
            return HttpResponseRedirect(redirect_to)
        except ValueError:
            pass
        ### these exceptions percolate up from AgentMultipleWidget
        ### in the value_from_datadict method
        except NoAgent, e:
            name = e.args[0]
            kw = {"agent-name": name}
            form = forms.form_for_model(Agent)(kw, prefix="agent")
        except NoUniqueAgent, e:
            agents = e.args[0]
            choices = [(a.id, str(a)) for a in agents]
            ### Construt a small form for the list of matching agents
            class Form(forms.Form):
                agents = forms.MultipleChoiceField(choices=choices)
            form = Form(prefix="agent_select")

    context = {
        'form' : form,
        'object' : object,
        'baseurl' : settings.WWW_BASEURL,    
    }

    c = RequestContext(request, context)
    t = loader.get_template(template)
    return HttpResponse(t.render(c))
 
# workaround - see 
def detach_dataset_agent(request,pk=None,agent_id=None):
    dataset = get_object_or_404(DataSet,pk=pk)
    agent = get_object_or_404(Agent,pk=agent_id)    
    contacts = list(dataset.contacts.filter())
    dataset.contacts.clear()
    new = []
    for c in contacts:
        if c != agent:
            new.append(c)
    dataset.contacts = new
    redirect_to = settings.WWW_BASEURL+'dataset/%s/extend/contact' % dataset.id
    return HttpResponseRedirect(redirect_to)

def edit_format(request,pk=None):
    return edit_object(request,'register','DataFormat',pk)

# timespan utils - should remember which dataset we are working from 
def edit_timespan(request, model=None, pk=None, template='register/edit_timespan.html'):
    # this will apply either to a dataset or datasource, depending on 'model'
    model_class = get_model('register',model) 
    print model_class
    data = get_object_or_404(model_class,pk=pk)
    print data     
    Form = forms.form_for_model(TimePeriod)
    if data.timespan is not None:
        Form = forms.form_for_instance(data.timespan) 
    if not request.POST:
        form = Form() 
    else:
        form = Form(request.POST)
        # only try to save if we're connected to a dataset
        try:
            @commit_on_success
            def validate(form):
                return form.save()
            object = validate(form)
            #if data.timespan is None:
            data.timespan = object
            data.save()
            # here, go on to add more properties
            redirect_to = settings.WWW_BASEURL+model.lower()+"/%s/" % data.id
            return HttpResponseRedirect(redirect_to)
        except ValueError:
            pass

    context = {
        'form' : form,
        'baseurl': settings.WWW_BASEURL,
    }

    c = RequestContext(request, context)
    t = loader.get_template(template)
    return HttpResponse(t.render(c))

def add_dataset_extents(request, pk=None, template='register/add_dataset_extents.html'):
    dataset = get_object_or_404(DataSet,pk=pk)
    if request.POST:
        #
        from duetopia.register.geo import box_as_wkt

        left = request.POST['left']
        right = request.POST['right']
        top = request.POST['top']
        bottom = request.POST['bottom']

        wkt = box_as_wkt((left, bottom,right,top))
        try:
            dataset.extents = wkt
            dataset.save()
            redirect_to = settings.WWW_BASEURL+"dataset/%s/" % dataset.id
            return HttpResponseRedirect(redirect_to)

        except ValueError:
            pass
    
    context = { 'tilecache': settings.TILECACHE,
                'baseurl': settings.WWW_BASEURL,
                'dataset':dataset }
    if dataset.extents is not None:
        context['top'] = dataset.extents.tuple[0][2][1]
        context['bottom'] = dataset.extents.tuple[0][0][1]
        context['left'] = dataset.extents.tuple[0][0][0]
        context['right'] = dataset.extents.tuple[0][2][0]

    c = RequestContext(request, context)
    t = loader.get_template(template)
    return HttpResponse(t.render(c))
 
 

